/*
    Copyright is LuoYuShun to 2022-2022
*/
package cn.com.laya.service.fourdemo.utils;

import cn.com.laya.service.fourdemo.bean.WebSocketMessage;
import cn.com.laya.service.fourdemo.deals.WebSocketMessageFactory;
import cn.com.laya.service.fourdemo.enums.MessageTypeEnum;
import cn.com.laya.service.fourdemo.websocket.WebSocket;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.websocket.Session;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * websocket的工具信息
 *
 * @author LuoYuShun
 * @since 2022-11-24
 */
@Slf4j
public class WebSocketUtils {
    /**
     * 禁止创建工具类
     */
    private WebSocketUtils() {
    }

    /**
     * 登录用户的map信息
     */
    private static final ConcurrentMap<String, WebSocket> CLIENT_MAP = new ConcurrentHashMap<>(100);

    /**
     * 获取场景的登录人的信息
     *
     * @param sceneNo 场景号
     * @return 返回登录人信息
     */
    public static List<WebSocket> getWebSocketClient(String sceneNo) {
        return CLIENT_MAP.values().stream().filter(item -> item.getScenario().equals(sceneNo))
                .collect(Collectors.toList());
    }

    /**
     * 获取对象
     *
     * @param username 账号
     * @return 返回账号信息
     */
    public static WebSocket getWebSocket(String username) {
        return CLIENT_MAP.get(username);
    }

    /**
     * 位置：移动容器
     */
    private static final ConcurrentMap<String, WebSocketMessage> POSITION = new ConcurrentHashMap<>(100);

    /**
     * 获取位置信息
     *
     * @return 返回信息
     */
    public static ConcurrentMap<String, WebSocketMessage> getPosition() {
        return POSITION;
    }

    /**
     * 获取位置的列表信息
     *
     * @param sceneNo 场景号
     * @return 返回位置的列表
     */
    public static List<WebSocketMessage> getWebSocketMessagePosition(String sceneNo) {
        return getWebSocketMessage(POSITION.values(), sceneNo);
    }

    /**
     * 旋转：旋转的容器
     */
    private static final ConcurrentMap<String, WebSocketMessage> ROTATION = new ConcurrentHashMap<>(100);

    /**
     * 获取旋转的类型
     *
     * @return 返回旋转的类型
     */
    public static ConcurrentMap<String, WebSocketMessage> getRotation() {
        return ROTATION;
    }

    /**
     * 获取旋转的数据
     *
     * @param sceneNo 场景编码
     * @return 返回消息列表
     */
    public static List<WebSocketMessage> getWebSocketMessageRotation(String sceneNo) {
        return getWebSocketMessage(ROTATION.values(), sceneNo);
    }

    /**
     * 配置信息
     */
    private static final ConcurrentMap<String, WebSocketMessage> CONFIG = new ConcurrentHashMap<>(100);

    /**
     * 数据的配置信息
     *
     * @param sceneNo 场景号
     * @return 返回信息
     */
    public static List<WebSocketMessage> getWebSocketMessageConfig(String sceneNo) {
        List<String> usernameList = CLIENT_MAP.values().stream().filter(item -> item.getScenario().equals(sceneNo))
                .map(WebSocket::getUsername).collect(Collectors.toList());
        return CONFIG.values().stream().filter(item -> usernameList.contains(item.getAccount()))
                .collect(Collectors.toList());
    }

    /**
     * 获取配置
     *
     * @return 返回信息
     */
    public static ConcurrentMap<String, WebSocketMessage> getConfig() {
        return CONFIG;
    }

    /**
     * 获取旋转的数据
     *
     * @param webSocketMessages 信息
     * @param sceneNo           场景编号
     * @return 返回信息
     */
    private static List<WebSocketMessage> getWebSocketMessage(Collection<WebSocketMessage> webSocketMessages, String sceneNo) {
        return webSocketMessages.stream().filter(item -> item.getScenario().equals(sceneNo))
                .collect(Collectors.toList());
    }

    /**
     * 动态的头像
     */
    private static final ConcurrentMap<String, WebSocketMessage> HEAD_IMG = new ConcurrentHashMap<>(100);

    /**
     * 获取头像的图片信息
     *
     * @return 返回头像的map
     */
    public static ConcurrentMap<String, WebSocketMessage> getHeadImg() {
        return HEAD_IMG;
    }

    /**
     * 头像的数据信息
     *
     * @param sceneNo 场景编号
     * @return 返回信息
     */
    public static List<WebSocketMessage> getWebSocketMessageHeadImg(String sceneNo) {
        return getWebSocketMessage(HEAD_IMG.values(), sceneNo);
    }

    /**
     * 添加客户端的信息
     *
     * @param username  用户名称
     * @param webSocket websocket端
     */
    public static void addClient(String username, WebSocket webSocket) {
        CLIENT_MAP.put(username, webSocket);
    }

    /**
     * 添加动作的信息
     *
     * @param message 消息
     */
    public static void addAction(String message, Session session) {
        if (StringUtils.isEmpty(message)) {
            log.error("接收的数据为空，不能进行处理 sessionId = {}", session.getId());
        }
        WebSocketMessage webSocketMessage = JSON.parseObject(message, WebSocketMessage.class);
        WebSocketMessageFactory webSocketMessageFactory = SpringContextUtils.getBean(WebSocketMessageFactory.class);
        webSocketMessageFactory.dealMessage(webSocketMessage, null);
    }

    /**
     * 删除客户端数据
     *
     * @param username 用户的账号
     */
    public static void removeClient(String username) {
        // 进行删除位置
        POSITION.remove(username);
        // 进行删除旋转
        POSITION.remove(username);
        // 进行删除头像
        HEAD_IMG.remove(username);
    }

    /**
     * 用户进行登出了的话，需要通知其他的服务器的对应的数据信息
     *
     * @param username 登录账号
     */
    public static void logout(String username) {
        // 进行发送推出的消息，如果有其他的容器，还需要进行通知一下其他发服务器。
        WebSocketMessage webSocketMessage = new WebSocketMessage();
        webSocketMessage.setAccount(username);
        webSocketMessage.setMessageType(MessageTypeEnum.LOGOUT.getType());
        webSocketMessage.setMsg("我下线了，不要发送信息给我了！我栓Q了。");
        CLIENT_MAP.remove(username);
        sendMessage(JSON.toJSONString(Collections.singletonList(webSocketMessage)), new ArrayList<>(CLIENT_MAP.values()));
        // 这里进行通知其他的服务器，可以使用消息队列中间件，可以使用rpc进行通知。
        removeClient(username);
    }

    /**
     * 发送消息
     *
     * @param message    消息信息
     * @param webSockets 客户端
     */
    public static void sendMessage(String message, List<WebSocket> webSockets) {
        for (WebSocket webSocket : webSockets) {
            if (!webSocket.getSession().isOpen()) {
                continue;
            }
            sendMessage(message, webSocket);
        }
    }

    /**
     * 发送消息出去
     *
     * @param message 消息信息
     */
    public static void sendMessage(String message, WebSocket webSocket) {
        synchronized (CLIENT_MAP.get(webSocket.getUsername())) {
            try {
                webSocket.getSession().getBasicRemote().sendText(message);
            } catch (Exception e) {
                log.error("发送消息失败 {}", webSocket.getUsername(), e);
            }
        }
    }
}
